<?php
/**
 * <b>RUBIK IT Solution & Development ltd.</b>
 *
 * PROJECT		: Rubik Ultimate Framework
 * @version 	: 1.1
 * COPYRIGHT    : 2008
 * ------------------------------------------------------
 * 
 * Created on	:  Jun 19, 2008
 * 
 */

// no direct access
defined ( '_FW_EXEC' ) or die ( 'Restricted access' );

class RFileFolderHelper {
	/**
	 * Utility static function to read the files in a folder
	 *
	 * @param	string	$path		The path of the folder to read
	 * @param	string	$filter		A filter for file names
	 * @param	mixed	$recurse	True to recursively search into sub-folders, or an integer to specify the maximum depth
	 * @param	boolean	$fullpath	True to return the full path to the file
	 * @return	array	Files in the given folder
	 * @since 1.5
	 */
	static function files($path, $filter = '.', $recurse = false, $fullpath = false) {
		// Initialize variables
		$arr = array ();
		$config = SystemSite::getSiteConfig ();
		// Is the path a folder?
		if (! is_dir ( $path ) && ! empty ( $config->debug )) {
			RError::raiseWarning ( 21, 'RFileFolderHelper::files: ' . SysLanguage::_ ( 'Path is not a folder' ) . ' ' . $path );
			return false;
		}
		
		// read the source directory
		$handle = opendir ( $path );
		while ( ($file = readdir ( $handle )) !== false ) {
			$dir = $path . DS . $file;
			$isDir = is_dir ( $dir );
			if (($file != '.') && ($file != '..') && (strpos ( $dir, '.svn' ) == false)) {
				if ($isDir) {
					if ($recurse) {
						if (is_integer ( $recurse )) {
							$recurse --;
						}
						$arr2 = RFileFolderHelper::files ( $dir, $filter, $recurse, $fullpath );
						$arr = array_merge ( $arr, $arr2 );
					}
				} else {
					if (preg_match ( "/$filter/", $file )) {
						if ($fullpath) {
							$arr [] = $path . DS . $file;
						} else {
							$arr [] = $file;
						}
					}
				}
			}
		}
		closedir ( $handle );
		//		asort($arr);
		return $arr;
	}
	
	/**
	 * Utility static function to read the folders in a folder
	 *
	 * @param	string	$path		The path of the folder to read
	 * @param	string	$filter		A filter for folder names
	 * @param	mixed	$recurse	True to recursively search into sub-folders, or an integer to specify the maximum depth
	 * @param	boolean	$fullpath	True to return the full path to the folders
	 * @return	array	Folders in the given folder
	 * 
	 */
	static function folders($path, $filter = '.', $recurse = false, $fullpath = false) {
		// Initialize variables
		$arr = array ();
		
		// Is the path a folder?
		$config = SystemSite::getSiteConfig ();
		if (! is_dir ( $path ) && ! empty ( $config->debug )) {
			RError::raiseWarning ( 21, 'RFileFolderHelper::folder: ' . SysLanguage::_ ( 'Path is not a folder' ) . ' ' . $path );
			return false;
		}
		
		// read the source directory
		$handle = opendir ( $path );
		while ( ($file = readdir ( $handle )) !== false ) {
			$dir = $path . DS . $file;
			$isDir = is_dir ( $dir );
			if (($file != '.') && ($file != '..') && $isDir) {
				// removes SVN directores from list
				if (preg_match ( "/$filter/", $file )) {
					if ($fullpath) {
						$arr [] = $dir;
					} else {
						$arr [] = $file;
					}
				}
				if ($recurse) {
					if (is_integer ( $recurse )) {
						$recurse --;
					}
					$arr2 = RFileFolderHelper::folders ( $dir, $filter, $recurse, $fullpath );
					$arr = array_merge ( $arr, $arr2 );
				}
			}
		}
		closedir ( $handle );
		
		//		asort($arr);
		return $arr;
	}
	
	/**
	 * Upload and move the uploaded file into input folder.
	 *
	 * @param string $inputName the name of submitted inputFile
	 * @param string $folder destination folder
	 * @param $aTypeUpload array type allow for upload
	 * 
	 * @return UploadFile
	 */
	static function uploadFileExt($inputName, $folder, $aTypeUpload = array( "jpg", "jpeg", "png", "gif", "bmp" )) {
		RCoreImporter::cls( "base.UploadFile" );
		$result = new UploadFile ( );
		
		if (! empty ( $_FILES [$inputName] ['error'] )) {
			switch ($_FILES [$inputName] ['error']) {
				
				case '1' :
					$error = 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
					break;
				case '2' :
					$error = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
					break;
				case '3' :
					$error = 'The uploaded file was only partially uploaded';
					break;
				case '4' :
					$error = 'No file was uploaded.';
					break;
				
				case '6' :
					$error = 'Missing a temporary folder';
					break;
				case '7' :
					$error = 'Failed to write file to disk';
					break;
				case '8' :
					$error = 'File upload stopped by extension';
					break;
				case '999' :
				default :
					$error = 'No error code avaiable';
			}
		} elseif (empty ( $_FILES [$inputName] ['tmp_name'] ) || $_FILES [$inputName] ['tmp_name'] == 'none') {
			$error = 'No file was uploaded..';
		} else {
			RCoreImporter::cls("helper.RFileFolderHelper" );
			$result->fileName = RFileFolderHelper::cleanFileName($_FILES [$inputName] ['name']);
			$result->fileSize = @filesize ( $_FILES [$inputName] ['tmp_name'] );
			
			// Upload Files
			$filePath = RFileFolderHelper::uploadFile ( $_FILES [$inputName] ['tmp_name'], $result->fileName, $folder, $aTypeUpload );
			if ($filePath === false) {
				if (is_array ( $aTypeUpload )) {
					$aTypeUpload = implode ( ", ", $aTypeUpload );
				}
				$result->setError ( "File type(s) doesn\\'t support. ($aTypeUpload)" );
			} else {
				$len = strlen($folder) - 1;
				if ($folder[$len] == '/' || $folder[$len] == '\\' ) {
					$result->filePath = "{$folder}{$filePath}";
				}
				else {
					$result->filePath = "$folder/$filePath";
				}
			}
			
			//for security reason, we force to remove all uploaded file
			@unlink ( $_FILES [$inputName] );
		}
		
		if (! empty ( $error )) {
			$result->setError ( $error );
		}
		return $result;
	}
	
	/**
	 * Check the file exists or not
	 * If not then create that file (may be create folder first)
	 *
	 * @param string $stringPath
	 */
	static function checkAndCreateFile($stringPath) {
		if (file_exists ( $stringPath )) {
			return;
		}
		
		$stringPath = str_replace ( "\\", "/", $stringPath );
		$arrPath = explode ( "/", $stringPath );
		$lastIndex = count ( $arrPath ) - 1;
		$filename = $arrPath [$lastIndex];
		unset ( $arrPath [$lastIndex] );
		foreach ( $arrPath as $folder ) {
			$dir .= $folder . DS;
			if (! is_dir ( $dir )) {
				mkdir ( $dir );
			}
		}
		
		// create file
		$f = fopen ( $dir . DS . $filename, "w" );
		fclose ( $f );
	}
	
	/**
	 * Check the Folder exists or not
	 * If not then create that Folder (may be create folder first)
	 *
	 * @param string $stringPath
	 */
	static function checkAndCreateFolder($stringPath) {
		if (file_exists ( $stringPath )) {
			return;
		}
		
		$stringPath = str_replace(SYS_ROOT_PATH, '', $stringPath);
		$stringPath = str_replace ( "\\", "/", $stringPath );
		$arrPath = explode ( "/", $stringPath );
		$dir = SYS_ROOT_PATH;
		foreach ( $arrPath as $folder ) {
			if (!$folder) {
				continue;
			}
			$dir .= $folder . DS;
			if (! is_dir ( $dir )) {
				mkdir ( $dir );
			}
			$first = false;
		}
	}
	
	/**
	 * Download an url into a desfolder
	 *
	 * @param string $url
	 * @param string $desFolder
	 * @param boolean $changeNameWhenExist
	 * @return string the filename
	 */
	static function downloadFile($url, $desFolder, $changeNameWhenExist = true) {
		$arr = explode ( '/', $url );
		// file name is the last one:
		$fileName = $arr [count ( $arr ) - 1];
		
		if (empty ( $fileName )) {
			$fileName = time ();
		}
		
		if ($changeNameWhenExist) {
			$i = 1;
			$fileNameChk = $fileName;
			while ( file_exists ( $desFolder . $fileNameChk ) ) {
				$fileNameChk = "{$i}_{$fileName}";
				$i ++;
			}
			$fileName = $fileNameChk;
		}
		
		if (@copy ( $url, $desFolder . $fileName )) {
			return $fileName;
		}
		return false;
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Upload a file
	 *
	 * @param string $temp_file full file path in the temp folder
	 * @param string $file_name expected file name (if it available)
	 * @param string $folder folder for holding this file
	 * @param string/array $aTypeUpload accepted file type. If string --> ".jpg, jpeg, png". if array -> array( "jpg", "jpeg", "png", "gif", "bmp" )
	 * @return string file name ("none" if file type isn't in expected type)
	 */
	static function uploadFile($temp_file, $file_name, $folder, $aTypeUpload = array( "jpg", "jpeg", "png", "gif", "bmp" )) {
		if (is_array ( $aTypeUpload )) {
			$typeUpload = $aTypeUpload;
		} else {
			$typeUpload = explode ( ",", $aTypeUpload );
			foreach ( $typeUpload as $k => $v ) {
				$v = str_replace ( "*.", "", $v );
				$v = str_replace ( ".", "", $v );
				$v = trim ( $v );
				if ($v == "") {
					unset ( $typeUpload [$k] );
				} else {
					$typeUpload [$k] = $v;
				}
			}
		}

		if (! empty ( $typeUpload ) 
				&& ! in_array ( strtolower ( substr ( $file_name, - 3 ) ), $typeUpload ) 
				&& ! in_array ( strtolower ( substr ( $file_name, - 4 ) ), $typeUpload )){
			return false;
		}
		
		$sOriginalFileName = $file_name;
		$sExtension = RFileFolderHelper::getFileExtention ( $file_name );
		$sExtension = strtolower ( $sExtension );
		$iCounter = 0;
		$sServerDir = $folder;
		RFileFolderHelper::checkAndCreateFolder($folder);
		
		// special treat for feelthere
		global $file_upload_prefix;
		$file_name = $file_upload_prefix.$file_name;
		
		while ( true ) {
			// Compose the file path.
			$sFilePath = $sServerDir . $file_name;
			
			// If a file with that name already exists.
			if (is_file ( $sFilePath )) {
				$iCounter ++;
				$file_name = RFileFolderHelper::removeExtension ( $sOriginalFileName ) . '_' . $iCounter . '.' . $sExtension;
			} else {
				move_uploaded_file ( $temp_file, $sFilePath );
				
				if (is_file ( $sFilePath )) {
					$oldumask = umask ( 0 );
					chmod ( $sFilePath, 0777 );
					umask ( $oldumask );
				}
				else {
					return false;
				}
				clearstatcache ();
				break;
			}
			clearstatcache ();
		}
		return $file_name;
	}
	
	/**
	 * Get file extention
	 *
	 * @param string $filePath
	 * @return string
	 */
	static function getFileExtention($filePath) {
		return substr ( $filePath, (RStringHelper::lastIndexOf ( $filePath, '.' )) );
	}
	
	/**
	 * Get file name with extention
	 *
	 * @param string $filePath
	 * @return string
	 */
	static function getFileName($filePath) {
		$file = str_replace('\\', '/', $filePath);
		return substr ( $file, (RStringHelper::lastIndexOf ( $file, '/' )) );
	}
	
	/**
	 * Remove extension of file
	 *
	 * @param string $fileName
	 * @return string
	 */
	static function removeExtension($fileName) {
		return substr ( $fileName, 0, RStringHelper::lastIndexOf ( $fileName, "." ) - 1 );
	}
	
	/**
	 *	Scope: Public
	 *  TODO: change this to clearly struct in params
	 */
	static function unzip() {
		$iParNum = func_num_args ();
		$aPar = func_get_args ();
		
		$sPackagePath = $aPar [0]; // absolute path to zip file
		$sDesDir = $aPar [1]; // Path/Path2/Path3/
		

		RFileFolderHelper::makeDirFromString ( $sDesDir );
		$vZip = zip_open ( $sPackagePath );
		
		if ($vZip) {
			
			while ( $vZipEntry = zip_read ( $vZip ) ) {
				
				$sFileName = zip_entry_name ( $vZipEntry );
				
				if (strrpos ( $sFileName, "/" ) != (strlen ( $sFileName ) - 1)) {
					$sFilePath = $sDesDir . $sFileName;
					$sDirPath = substr ( $sFilePath, 0, strrpos ( $sFilePath, "/" ) );
					RFileFolderHelper::makeDirFromString ( $sDirPath );
					zip_entry_open ( $vZip, $vZipEntry, "r" );
					$sSize = zip_entry_filesize ( $vZipEntry ) + 1;
					$vBuf = zip_entry_read ( $vZipEntry, $sSize );
					$vFp = fopen ( $sFilePath, "a+" );
					fwrite ( $vFp, $vBuf );
					fclose ( $vFp );
					zip_entry_close ( $vZipEntry );
				}
			
			}
			
			zip_close ( $vZip );
		
		}
	
	}
	
	/**
	 *	Scope: Public
	 *  TODO: change this to clearly struct in params
	 * 	 */
	static function makeDirFromString() {
		$iParNum = func_num_args ();
		$aPar = func_get_args ();
		
		if ($iParNum == 1)
			$sPath = $aPar [0]; # Path1/Path2/Path3/
		

		$aPath = explode ( "/", $sPath );
		$sNewPath = "";
		foreach ( $aPath as $v ) {
			$sNewPath .= $v;
			if (! in_array ( $v, array ("", ".", ".." ) ) && ! is_dir ( $sNewPath )) {
				mkdir ( $sNewPath, 0777 );
			}
			$sNewPath .= "/";
		}
	
	}
	
	/*
	 *	Scope: Public
	 *  TODO: change this to clearly struct in params
	 * 	 */
	static function copyDir() {
		$iParNum = func_num_args ();
		$aPar = func_get_args ();
		
		$sSrcDir = $aPar [0]; // Path1/Path2/Path3
		$sDesDir = $aPar [1]; // Path1/Path2/Path3
		if ($iParNum == 3)
			$sFPatern = $aPar [2]; // File name pattern (perl)
		

		$vDirHandle = opendir ( $sSrcDir );
		$aFiles = array ();
		$aDirs = array ();
		$aNotChosenFiles = array (".", ".." );
		$aNotChosenDirs = array (".", ".." );
		while ( false !== ($sFileName = readdir ( $vDirHandle )) ) {
			if (is_dir ( $sSrcDir . "/" . $sFileName ) && ! in_array ( $sFileName, $aNotChosenDirs )) {
				$aDirs [] = $sFileName;
			} else if (! in_array ( $sFileName, $aNotChosenFiles )) {
				if ($iParNum == 3) {
					if (preg_match ( $sFPattern, $sFileName )) {
						$aFiles [] = $sFileName;
					}
				} else {
					$aFiles [] = $sFileName;
				}
			}
		}
		
		if (count ( $aFiles ) > 0) {
			foreach ( $aFiles as $k => $v ) {
				RFileFolderHelper::makeDirFromString ( $sDesDir );
				copy ( $sSrcDir . "/" . $v, $sDesDir . "/" . $v );
			}
		}
		
		foreach ( $aDirs as $v ) {
			if ($iParNum == 3)
				RFileFolderHelper::copyDir ( $sSrcDir . "/" . $v, $sDesDir . "/" . $v, $sFPatern );
			else
				RFileFolderHelper::copyDir ( $sSrcDir . "/" . $v, $sDesDir . "/" . $v );
		}
		
		closedir ( $vDirHandle );
	}
	
	/*
	 *	Scope: Public
	 *  TODO: change this to clearly struct in params
	 * 	 */
	static function removeDir() {
		$iParNum = func_num_args ();
		$aPar = func_get_args ();
		
		$sSrcDir = $aPar [0]; // Path1/Path2/Path3
		if ($iParNum == 2)
			$sFPatern = $aPar [1]; // File name pattern (perl)
		

		$vDirHandle = opendir ( $sSrcDir );
		$aFiles = array ();
		$aDirs = array ();
		$aNotChosenFiles = array (".", ".." );
		$aNotChosenDirs = array (".", ".." );
		while ( false !== ($sFileName = readdir ( $vDirHandle )) ) {
			if (is_dir ( $sSrcDir . "/" . $sFileName ) && ! in_array ( $sFileName, $aNotChosenDirs )) {
				$aDirs [] = $sFileName;
			} else if (! in_array ( $sFileName, $aNotChosenFiles )) {
				if ($iParNum == 2) {
					if (preg_match ( $sFPattern, $sFileName )) {
						$aFiles [] = $sFileName;
					}
				} else {
					$aFiles [] = $sFileName;
				}
			}
		}
		
		if (count ( $aFiles ) > 0) {
			foreach ( $aFiles as $k => $v ) {
				unlink ( $sSrcDir . "/" . $v );
			}
		}
		
		foreach ( $aDirs as $v ) {
			if ($iParNum == 2)
				RFileFolderHelper::removeDir ( $sSrcDir . "/" . $v, $sFPatern );
			else
				RFileFolderHelper::removeDir ( $sSrcDir . "/" . $v );
		}
		
		closedir ( $vDirHandle );
		rmdir ( $sSrcDir );
	}
	
	// path input without '/' at last
	// return array of file names order by file name asc
	//  TODO: change this to clearly struct in params
	static function getFilesFromDir() {
		$iParNum = func_num_args ();
		$aPar = func_get_args ();
		
		$sSrcDir = $aPar [0]; // Path1/Path2/Path3
		if ($iParNum == 2)
			$sFPatern = $aPar [1]; // File name pattern (perl)
		

		if (! is_dir ( $sSrcDir ))
			return array ();
		
		$vDirHandle = opendir ( $sSrcDir );
		$aFiles = array ();
		$aDirs = array ();
		$aNotChosenFiles = array (".", ".." );
		$aNotChosenDirs = array (".", ".." );
		while ( false !== ($sFileName = readdir ( $vDirHandle )) ) {
			if (is_file ( $sSrcDir . "/" . $sFileName ) && ! in_array ( $sFileName, $aNotChosenFiles )) {
				if ($iParNum == 2) {
					if (preg_match ( $sFPatern, $sFileName )) {
						$aFiles [] = $sFileName;
					}
				}
			}
		}
		
		closedir ( $vDirHandle );
		sort ( $aFiles );
		return $aFiles;
	}
	
	static function cleanFileName($fileName) {
		// Get extension of fileName
		$fileExt = RFileFolderHelper::getFileExtention($fileName);
		// remove file ext
		$fileName = str_replace('.'.$fileExt, '', $fileName);
   		return preg_replace("/[^A-Za-z0-9-]/","_",$fileName).'.'.$fileExt;
	}
	
	/**
	 * Create binary http streaming from a file.
	 * @param $filePath
	 * @return unknown_type
	 */
	static function createHttpStreamFile($filePath) {
		$fileName = RFileFolderHelper::getFileName($filePath);
		header('Content-type: application/octet-stream');
		header('Content-disposition: attachment; filename="'.$fileName.'"');
		header('Content-length: ' . filesize($filePath));
		
		echo file_get_contents($filePath, FILE_BINARY);
	}
}
